﻿package com.urbansquall.chaos
{
	/**
	* Authored and donated by iopred of http://www.squarecircleco.com/, the man, the myth, the miracle.
	*/
	
	public class PseudoRandom
	{
		private static var m_instance:PseudoRandom;
		
		private var m_initialSeed:uint;
		private var m_seed:uint;
		
		public function PseudoRandom(a_seed:uint = 1)
		{
			if (a_seed == 0 || a_seed >= uint(uint.MAX_VALUE/2))
			{
				a_seed = 1;
			}
			seed = a_seed;
		}
		
		public function random() : Number
		{
			return ( nextRand() / 2147483647 );
		}
		
		public function randomRange( a_minimum : Number, a_maximum : Number = NaN ) : Number
		{
			if (isNaN(a_maximum))
			{
				a_maximum = a_minimum;
				a_minimum = 0;
			}
			
			return a_minimum + random() * ( a_maximum - a_minimum );
		}
				
		public function boolean( a_chance : Number = 0.5 ):Boolean
		{
			return random() < a_chance;
		}
		
		public function sign( a_chance : Number = 0.5 ) : int
		{
			return ( random() < a_chance ? 1 : -1);
		}
		
		public function reset():void
		{
			m_seed = m_initialSeed;
		}
		
		public function get seed() : uint { return m_initialSeed; }
		
		public function set seed( a_value : uint ) : void
		{
			m_initialSeed = m_seed = a_value;
		}
		
		public static function get instance() : PseudoRandom
		{
			if( m_instance == null )
			{
				m_instance = new PseudoRandom();
			}
			
			return m_instance;
		}
		
		public static function random() : Number
		{
			return instance.random();
		}
		
		public static function randomRange( a_minimum : Number, a_maximum : Number ):Number
		{
			return instance.randomRange( a_minimum, a_maximum );
		}
		
		public static function boolean( chance : Number = 0.5 ):Boolean
		{
			return instance.boolean( chance );
		}
		
		public static function sign( chance : Number = 0.5 ):int
		{
			return instance.sign( chance );
		}
		
		public static function reset():void
		{
			instance.reset();
		}
		
		public static function get seed() : uint { return instance.seed; }
		
		public static function set seed( a_value : uint ) : void
		{
			instance.seed = a_value;
		}
		
		private function nextRand():uint
		{
			return m_seed = ( m_seed * 16807 ) % 2147483647;
		}
	}
	
}